/*****************************************************************************
 *  ENTROPY - emerging network to reduce orwellian potency yield
 *
 *  Copyright (C) 2002 Juergen Buchmueller <pullmoll@stop1984.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software Foundation,
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 *	$Id: temp.c,v 1.6 2005/07/19 13:06:39 pullmoll Exp $
 *****************************************************************************/
#include "osd.h"
#include "config.h"
#include "memalloc.h"
#include "shmalloc.h"
#include "tools.h"
#include "temp.h"
#include "logger.h"

#define	TEMP_MEMORY_FD	-2

int temp(void)
{
	char filename[MAXPATHLEN];
	struct stat st;
	DIR *dir;
	struct dirent *de;
	size_t len = strlen(g_conf->progname);
	FUN("temp");

	if (0 != stat(g_conf->temppath, &st) || !S_ISDIR(st.st_mode)) {
		/* if it is a file, unlink it */
		unlink(g_conf->temppath);
		if (0 == mkdir(g_conf->temppath, 0700)) {
			info("Created temp dir '%s'; \n", g_conf->temppath);
			return 0;
		}
		info("Temp dir '%s' error (%s) ",
			g_conf->temppath, strerror(errno));
		return -1;
	}

	dir = opendir(g_conf->temppath);
	if (NULL == dir) {
		info("Temp dir '%s' error (%s) ",
			g_conf->temppath, strerror(errno));
		return -1;
	}
	info("cleaning temp dir '%s' ", g_conf->temppath);
	/* clean out the old temp files that might have been left... */
	while (NULL != (de = readdir(dir))) {
		if (strncmp(de->d_name, g_conf->progname, len)) {
			continue;	/* skip files that do not begin with <progname> */
		}
		pm_snprintf(filename, sizeof(filename), "%s/%s",
			g_conf->temppath, de->d_name);
		unlink(filename);
	}
	closedir(dir);
	return 0;
}

/**
 * @brief Initialize a tempfile_t to state invalid.
 *
 * Initialize a tempfile_t to state invalid.
 *
 * @param tf Pointer to a tempfile_t to be initialized.
 *
 * @result return zero on success, -1 and errno set to EINVAL for bad args
 */
int _temp_invalid(tempfile_t *tf FILE_LINE_ARGS)
{
	FUN("temp_invalid");

#if	TMP_DEBUG
	LOG(L_DEBUGX,("called from %s.%d\n", file, line));
#endif
	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	/* set defaults */
	tf->type = TEMP_INVALID;
	tf->fd = -1;
	tf->name[0] = '\0';
	tf->data = NULL;
	tf->rpos = 0;
	tf->wpos = 0;
	tf->wmax = 0;
	tf->size = 0;

	return 0;
}

/**
 * @brief Create a temporary file in binary mode.
 *
 * Use mkstemp to create a temp file from a filename template.
 * For CYGWIN users create a temp file in binary mode.
 *
 * @param tf Pointer to a tempfile_t to be set up.
 * @param name Pointer to a string with the name for the temp file.
 * @param size Expected (or known) size of the temp file.
 *
 * @result return zero on success, -1 and errno set to EINVAL for bad args
 */
int _temp_binary(tempfile_t *tf, const char *name, size_t size FILE_LINE_ARGS)
{
	int fd = -1;
	FUN("temp_binary");

#if	TMP_DEBUG
	LOG(L_DEBUGX,("called from %s.%d\n", file, line));
#endif
	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	/* set defaults */
	tf->type = TEMP_INVALID;
	tf->fd = -1;
	pm_snprintf(tf->name, sizeof(tf->name), "%s", name);
	tf->data = NULL;
	tf->rpos = 0;
	tf->wpos = 0;
	tf->wmax = 0;
	tf->size = 0;

	if (size > 0 && size < TEMP_MEMORY_LIMIT) {
		tf->data = xmalloc(size);
		if (NULL == tf->data) {
			errno = ENOMEM;
			return -1;
		}
		tf->size = size;
		tf->fd = TEMP_MEMORY_FD;
		tf->type = TEMP_MEMORY;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d created %d bytes M'%s'\n",
			file, line, (unsigned)size, tf->name));
#else
		LOG(L_DEBUG,("created %d bytes M'%s'\n",
			(unsigned)size, tf->name));
#endif

	} else if (0 == size || TEMP_UNKNOWN_SIZE == size) {
		tf->data = NULL;
		tf->size = 0;
		tf->fd = TEMP_MEMORY_FD;
		tf->type = TEMP_EXPANDABLE;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d created X'%s'\n",
			file, line, tf->name));
#else
		LOG(L_DEBUG,("created X'%s'\n",
			tf->name));
#endif
	} else {
		char *path = xmalloc(MAXPATHLEN);

#ifdef	__CYGWIN__
		pm_snprintf(path, MAXPATHLEN, "%s/%s-%s.%d",
			g_conf->temppath, g_conf->progname, name, getpid());
		fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
		if (-1 == fd) {
			LOG(L_ERROR,("open('%s', O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666) call failed (%s)\n",
				path, strerror(errno)));
			xfree(path);
			return -1;
		}
#else
		pm_snprintf(path, MAXPATHLEN, "%s/%s-%s.%d.XXXXXX",
			g_conf->temppath, g_conf->progname, name, getpid());
		fd = mkstemp(path);
		if (-1 == fd) {
			LOG(L_ERROR,("mkstemp('%s') call failed (%s)\n",
				path, strerror(errno)));
			xfree(path);
			return -1;
		}
#endif
		tf->fd = fd;
		tf->data = path;
		tf->size = size;
		tf->type = TEMP_FILESYSTEM;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d created %d bytes F'%s'\n",
			file, line, (unsigned)size, tf->name));
#else
		LOG(L_DEBUG,("created %d bytes F'%s'\n",
			(unsigned)size, tf->name));
#endif
	}

	return 0;
}

/**
 * @brief Create a temporary file in binary mode and close it.
 *
 * Use mkstemp to create a filename template and close it.
 * This will be used for temporary files that are written
 * to later.
 *
 * @param tf Pointer to a tempfile_t to be set up.
 * @param name Pointer to a string with the name for the temp file.
 * @param size Expected (or known) size of the temp file.
 *
 * @result return zero on success, -1 and errno set to EINVAL for bad args
 */
int _temp_closed(tempfile_t *tf, const char *name, size_t size FILE_LINE_ARGS)
{
	int rc;
	FUN("temp_closed");

#if	TMP_DEBUG
	(void)file;
	(void)line;
#endif
	/* create a temp file in binary mode (CYGWIN) */
	rc = _temp_binary(tf, name, size FILE_LINE_PARMS);

	if (0 == rc) {
		/* and close it */
		rc = _temp_close(tf, 0 FILE_LINE_PARMS);
	}
	return rc;
}

/**
 * @brief Open or re-open a temporary file.
 *
 * Opens or re-opens a temporary file. For in-memory temp
 * files this is simply setting pseudo-fd and offset to zero.
 * For filesystem temp files this function calls open()
 *
 * @param tf Pointer to a tempfile_t to (re-)open.
 *
 * @result return zero on success, otherwise -1 and errno set
 */
int _temp_open(tempfile_t *tf FILE_LINE_ARGS)
{
	int fd = -1;
	FUN("temp_open");

	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	if (-1 != tf->fd) {
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d close temp %s\n",
			file, line, tf->name));
#else
		LOG(L_DEBUG,("close temp %s\n",
			tf->name));
#endif
		_temp_close(tf, 0 FILE_LINE_PARMS);
	}

	switch (tf->type) {
	case TEMP_MEMORY:
		tf->fd = TEMP_MEMORY_FD;
		tf->rpos = 0;
		tf->wpos = 0;
		tf->wmax = tf->size;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d M'%s' size %x\n",
			file, line, tf->name, (unsigned)tf->size));
#else
		LOG(L_DEBUG,("M'%s' size %x\n",
			tf->name, (unsigned)tf->size));
#endif
		break;
	case TEMP_EXPANDABLE:
		tf->fd = TEMP_MEMORY_FD;
		tf->rpos = 0;
		tf->wpos = 0;
		tf->wmax = tf->size;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d X'%s' size %x\n",
			file, line, tf->name, (unsigned)tf->size));
#else
		LOG(L_DEBUG,("X'%s' size %x\n",
			tf->name, (unsigned)tf->size));
#endif
		break;
	case TEMP_FILESYSTEM:
		fd = open(tf->data, O_RDWR|O_BINARY);
		if (-1 == fd) {
			LOG(L_ERROR,("open('%s', O_RDWR|O_BINARY) call failed (%s)\n",
				(char *)tf->data, strerror(errno)));
			return -1;
		}
		tf->fd = fd;
		tf->rpos = 0;
		tf->wpos = 0;
		tf->wmax = tf->size;
#if	TMP_DEBUG
		LOG(L_DEBUG,("%s.%d F'%s' size %x\n",
			file, line, tf->name, (unsigned)tf->size));
#else
		LOG(L_DEBUG,("F'%s' size %x\n",
			tf->name, (unsigned)tf->size));
#endif
		break;
	default:
		errno = EBADF;
		return -1;
	}
	return 0;
}

/**
 * @brief Seek to a specific file offset in a temp file.
 *
 * Seek to the specified position in the temp file - same as lseek(),
 * but handles in-memory temp files transparently to the caller.
 *
 * @param tf Pointer to a tempfile_t seek.
 * @param offs Offset in bytes, relative to: see whence.
 * @param whence One of SEEK_SET, SEEK_CUR, SEEK_END.
 *
 * @result return zero on success, otherwise -1 and errno set
 */
int _temp_seek(tempfile_t *tf, off_t offs, int whence FILE_LINE_ARGS)
{
	FUN("temp_seek");

	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	if (-1 == tf->fd) {
		LOG(L_ERROR,("seeking closed temp '%s'\n",
			tf->name));
		errno = EBADF;
		return -1;
	}

	switch (tf->type) {
	case TEMP_MEMORY:
	case TEMP_EXPANDABLE:
		switch (whence) {
		case SEEK_SET:
			tf->rpos = tf->wpos = offs;
#if	TMP_DEBUG
			LOG(L_DEBUGX,("%s.%d M/X'%s' seek set %x\n",
				file, line, tf->name, (unsigned)tf->wpos));
#else
			LOG(L_DEBUGX,("M/X'%s' seek set %x\n",
				tf->name, (unsigned)tf->wpos));
#endif
			break;
		case SEEK_CUR:
			tf->rpos = tf->wpos += offs;
#if	TMP_DEBUG
			LOG(L_DEBUGX,("%s.%d M/X'%s' seek cur %x\n",
				file, line, tf->name, (unsigned)tf->wpos));
#else
			LOG(L_DEBUGX,("M/X'%s' seek cur %x\n",
				tf->name, (unsigned)tf->wpos));
#endif
			break;
		case SEEK_END:
			tf->rpos = tf->wpos = tf->wmax + offs;
#if	TMP_DEBUG
			LOG(L_DEBUGX,("%s.%d M/X'%s' seek end %x\n",
				file, line, tf->name, (unsigned)tf->wpos));
#else
			LOG(L_DEBUGX,("M/X'%s' seek end %x\n",
				tf->name, (unsigned)tf->wpos));
#endif
			break;
		default:
			errno = EINVAL;
			return -1;
		}
		break;
	case TEMP_FILESYSTEM:
		if ((size_t)-1 == (tf->wpos = lseek(tf->fd, offs, whence))) {
			LOG(L_ERROR,("lseek('%s',0x%x,%d) call failed (%s)\n",
				tf->name, (unsigned)offs, whence,
				strerror(errno)));
			tf->rpos = tf->wpos;
			return -1;
		}
		tf->rpos = tf->wpos;
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d F'%s' seek to %x\n",
			file, line, tf->name, (unsigned)tf->wpos));
#else
		LOG(L_DEBUGX,("F'%s' seek to %x\n",
			tf->name, (unsigned)tf->wpos));
#endif
		break;
	default:
		errno = EBADF;
		return -1;
	}
	return 0;
}

/**
 * @brief Write data to a temp file.
 *
 * Write to a temporary file. This handles the type of
 * storage (memory, expandable or file system tempfile) transparently
 * for the caller.
 *
 * @param tf Pointer to a tempfile_t to write to.
 * @param buff Pointer to a buffer holding data to write.
 * @param size Number of bytes to write.
 *
 * @result return zero on success, otherwise -1 and errno set
 */
int _temp_write(tempfile_t *tf, const void *buff, size_t size FILE_LINE_ARGS)
{
	const uint8_t *src;
	uint8_t *dst;
	size_t done;
	FUN("temp_write");

	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	if (-1 == tf->fd) {
		LOG(L_ERROR,("writing closed temp '%s'\n",
			tf->name));
		errno = EBADF;
		return -1;
	}

	switch (tf->type) {
	case TEMP_MEMORY:
		src = buff;
		dst = tf->data;
		if (tf->wpos + size > tf->size) {
			LOG(L_ERROR,("writing '%s' failed (0x%x,0x%x) size 0x%x (%s)\n",
				tf->name, (unsigned)tf->wpos, (unsigned)tf->size,
				(unsigned)size, strerror(errno)));
			return -1;
		}
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d write M'%s' @%x size %x\n",
			file, line, tf->name, (unsigned)tf->wpos, (unsigned)size));
#else
		LOG(L_DEBUGX,("write M'%s' @%x size %x\n",
			tf->name, (unsigned)tf->wpos, (unsigned)size));
#endif
		memcpy(&dst[tf->wpos], buff, size);
		tf->wpos += size;
		break;

	case TEMP_EXPANDABLE:
		src = buff;
		dst = tf->data;

		/* check if we have to reallocate memory */
		if (tf->wpos + size > tf->size) {
			/* new size */
			tf->size = tf->wpos + size;

			/* time to 'convert' file into a file system type? */
			if (tf->size >= TEMP_MEMORY_LIMIT) {
				tempfile_t tf2;
				int rc;

#if	TMP_DEBUG
				LOG(L_DEBUG,("%s.%d write X'%s' to disk\n",
					file, line, tf->name));
#else
				LOG(L_DEBUG,("write X'%s' to disk\n",
					tf->name));
#endif
				if (0 != (rc = temp_binary(&tf2, tf->name, tf->size))) {
					/* geeezz.. that's too bad :-( */
					return rc;
				}
				/* write the part we already collected */
				if (0 != (rc = temp_write(&tf2, tf->data, tf->wpos))) {
					_temp_close(&tf2, 1 FILE_LINE_PARMS);
					return rc;
				}
				/* and now append the new data */
				if (0 != (rc = temp_write(&tf2, buff, size))) {
					_temp_close(&tf2, 1 FILE_LINE_PARMS);
					return rc;
				}
				/* free the memory of the caller's tempfile_t */
				if (NULL != tf->data) {
					xfree(tf->data);
					tf->data = NULL;
				}
				/* and copy the TEMP_FILESYSTEM type */
				*tf = tf2;
				return 0;
			}

#if	TMP_DEBUG
			LOG(L_DEBUGX,("%s.%d realloc X'%s' to size %x\n",
				file, line, tf->name, (unsigned)tf->size));
#else
			LOG(L_DEBUGX,("realloc X'%s' to size %x\n",
				tf->name, (unsigned)tf->size));
#endif
			/* the data still fits in memory */
			tf->data = xrealloc(tf->data, tf->size);
			if (NULL == tf->data) {
				LOG(L_ERROR,("reallocating X'%s' to size 0x%x failed (%s)\n",
					tf->name, (unsigned)tf->size, strerror(errno)));
				_temp_close(tf, 0 FILE_LINE_PARMS);
				errno = ENOMEM;
				return -1;
			}
			dst = tf->data;
		}

#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d write X'%s' @%x size %x\n",
			file, line, tf->name, (unsigned)tf->wpos, (unsigned)size));
#else
		LOG(L_DEBUGX,("write X'%s' @%x size %x\n",
			tf->name, (unsigned)tf->wpos, (unsigned)size));
#endif
		memcpy(&dst[tf->wpos], buff, size);
		tf->wpos += size;
		break;

	case TEMP_FILESYSTEM:
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d write F'%s' @%x size %x\n",
			file, line, tf->name, (unsigned)tf->wpos, (unsigned)size));
#else
		LOG(L_DEBUGX,("write F'%s' @%x size %x\n",
			tf->name, (unsigned)tf->wpos, (unsigned)size));
#endif
		done = write(tf->fd, buff, size);
		if (done != size) {
			LOG(L_ERROR,("write(%d,'%s',%p,%#x) failed (%s)\n",
				tf->fd, (char *)tf->data, buff, (unsigned)size,
				strerror(errno)));
			_temp_close(tf, 1 FILE_LINE_PARMS);
			return -1;
		}
		tf->wpos += done;
		break;

	case TEMP_INVALID:
	default:
		LOG(L_ERROR,("writing closed temp '%s'\n",
			tf->name));
		errno = EBADF;
		return -1;
	}

	/* adjust written-max size */
	if (tf->wpos > tf->wmax) {
		tf->wmax = tf->wpos;
	}

	return 0;
}

/**
 * @brief Read data from a temp file.
 *
 * Read from a temporary file. This handles the type of
 * storage (memory or file system tempfile) transparently for the caller.
 *
 * @param tf Pointer to a tempfile_t to read from.
 * @param buff Pointer to a buffer receiving the data.
 * @param size Number of bytes to read.
 * @param pdone Optional pointer to a size_t to receive number of bytes read.
 *
 * @result return zero on success, otherwise -1 and errno set
 */
int _temp_read(tempfile_t *tf, void *buff, size_t size, size_t *pdone FILE_LINE_ARGS)
{
	uint8_t *dst, *src;
	size_t done, have;
	FUN("temp_read");

	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	if (NULL != pdone) {
		*pdone = 0;
	}

	if (-1 == tf->fd) {
		LOG(L_ERROR,("reading closed file '%s'\n",
			tf->name));
		errno = EBADF;
		return -1;
	}

	/* read from a file that is still written to? */
	have = (tf->wmax > 0) ? tf->wmax : tf->size;

	switch (tf->type) {
	case TEMP_MEMORY:
		src = tf->data;
		dst = buff;
		if (tf->rpos >= have) {
			if (0 != tf->size) {
				/* errno (not EAGAIN) */
				errno = 0;
				return 0;
			}
			/* reading at end of open file: EAGAIN */
			errno = EAGAIN;
			return -1;
		}
		done = (tf->rpos + size > have) ?
			have - tf->rpos : size;
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d read M'%s' @%x size %x/%x\n",
			file, line, tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#else
		LOG(L_DEBUGX,("read M'%s' @%x size %x/%x\n",
			tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#endif
		memcpy(dst, &src[tf->rpos], done);
		tf->rpos += done;
		break;

	case TEMP_EXPANDABLE:
		src = tf->data;
		dst = buff;
		if (tf->rpos >= have) {
			if (0 != tf->size) {
				/* errno (not EAGAIN) */
				errno = 0;
				return 0;
			}
			/* reading at end of open file: EAGAIN */
			errno = EAGAIN;
			return -1;
		}
		done = (tf->rpos + size > have) ?
			have - tf->rpos : size;
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d read X'%s' @%x size %x/%x\n",
			file, line, tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#else
		LOG(L_DEBUGX,("read X'%s' @%x size %x/%x\n",
			tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#endif
		memcpy(dst, &src[tf->rpos], done);
		tf->rpos += done;
		break;

	case TEMP_FILESYSTEM:
		done = read(tf->fd, buff, size);
		if ((size_t)-1 == done) {
			LOG(L_ERROR,("read at end-of-file '%s'\n",
				tf->name));
			return -1;
		}
#if	TMP_DEBUG
		LOG(L_DEBUGX,("%s.%d read F'%s' @%x size %x/%x\n",
			file, line, tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#else
		LOG(L_DEBUGX,("read F'%s' @%x size %x/%x\n",
			tf->name, (unsigned)tf->rpos,
			(unsigned)done, (unsigned)size));
#endif
		tf->rpos += done;
		break;

	default:
		errno = EBADF;
		return -1;
	}

	/* set the caller's 'done' var */
	if (NULL != pdone) {
		*pdone = done;
	}
	return 0;
}

/**
 * @brief Close a temp file and clean up.
 *
 * Closes a temporary file; if dispose is non-zero, it also
 * unlinks the temporary file from the file system or frees
 * memory for in-memory temp files.
 *
 * @param tf Pointer to a tempfile_t to close.
 * @param dispose If non zero also unlink/free the file (no re-open).
 *
 * @result return zero on success, otherwise -1 and errno set
 */
int _temp_close(tempfile_t *tf, int dispose FILE_LINE_ARGS)
{
	FUN("temp_close");

	if (NULL == tf) {
		errno = EINVAL;
		return -1;
	}

	switch (tf->type) {
	case TEMP_MEMORY:
	case TEMP_EXPANDABLE:
		if (-1 != tf->fd) {
#if	TMP_DEBUG
			LOG(L_DEBUGX,("%s.%d resetting fake memory fd\n",
				file, line));
#else
			LOG(L_DEBUGX,("resetting fake memory fd\n"));
#endif
			tf->fd = -1;
			tf->rpos = 0;
			tf->wpos = 0;
			tf->size = tf->wmax;
			tf->wmax = 0;
		}
		if (0 == dispose)
			break;
		if (NULL != tf->data) {
#if	TMP_DEBUG
			LOG(L_DEBUG,("%s.%d free M/X'%s' @%p size %#x\n",
				file, line, tf->name,
				tf->data, (unsigned)tf->size));
#else
			LOG(L_DEBUG,("free M/X'%s' @%p size %#x\n",
				tf->name,
				tf->data, (unsigned)tf->size));
#endif
			xfree(tf->data);
			tf->data = NULL;
		}
		tf->rpos = 0;
		tf->wpos = 0;
		tf->wmax = 0;
		tf->size = 0;
		tf->type = TEMP_INVALID;
		break;
	case TEMP_FILESYSTEM:
		if (-1 != tf->fd) {
			close(tf->fd);
			tf->fd = -1;
			tf->rpos = 0;
			tf->wpos = 0;
			tf->size = tf->wmax;
			tf->wmax = 0;
		}
		if (0 == dispose)
			break;
		if (NULL != tf->data) {
#if	TMP_DEBUG
			LOG(L_DEBUG,("%s.%d unlink and free F'%s' file '%s'\n",
				file, line, tf->name, (char *)tf->data));
#else
			LOG(L_DEBUG,("unlink and free F'%s' file '%s'\n",
				tf->name, (char *)tf->data));
#endif
			if (0 != unlink(tf->data)) {
				LOG(L_DEBUG,("unlink('%s') failed (%s)\n",
					(char *)tf->data, strerror(errno)));
			}
			xfree(tf->data);
			tf->data = NULL;
		}
		tf->rpos = 0;
		tf->wpos = 0;
		tf->wmax = 0;
		tf->size = 0;
		tf->type = TEMP_INVALID;
		break;
	default:
		errno = EBADF;
		return -1;
	}

	return 0;
}

